﻿/* HEADER
 * ------
 * © 2009 by Salomon Zwecker 
 * modified by:
 * - 
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Shapes.Geometry
{

    /// <summary>
    /// The Angle Struct represents an Angle based on a radian value.
    /// </summary>
    public struct Angle : IEquatable<Angle>
    {
        /// <summary>
        /// Creates an <see cref="Angle"/> from degree.
        /// </summary>
        /// <param name="degree">The degree.</param>
        /// <returns></returns>
        public static Angle CreateFromDegree(float degree)
        {
            return new Angle(MathHelper.ToRadians(degree));
        }

        /// <summary>
        /// Creates an <see cref="Angle"/> from a direction vector.
        /// </summary>
        /// <param name="direction">The direction.</param>
        public static Angle CreateFromVector(Vector2 direction)
        {
            Angle a = new Angle(0);
            a.SetDirectionVector(direction);
            return a;
        }


        private float _Radians;
        /// <summary>
        /// Gets or sets the radians, which is a value between -PI and +PI.
        /// </summary>
        public float Radians 
        { 
            get { return _Radians; }
            set {
                _Radians = MathHelper.WrapAngle(value);
                //while (value < -MathHelper.Pi) 
                //    value += MathHelper.TwoPi;

                //if (value <= MathHelper.Pi)
                //    _Radians = value;
                //else
                //    _Radians = value % MathHelper.TwoPi - MathHelper.Pi; 
            }
        }
        /// <summary>
        /// Gets or sets the clockwise (inverted) radians. Spritebatch.Draw() for example needs this value.
        /// </summary>
        public float ClockwiseRadians { get { return -_Radians; } set { Radians = -value; } }


        /// <summary>
        /// Gets or sets the degree.
        /// </summary>
        public float Degree { get { return MathHelper.ToDegrees(_Radians); } set { Radians = MathHelper.ToRadians(value); } }
        /// <summary>
        /// Gets or sets the clockwise (inverted) degree.
        /// </summary>
        public float ClockwiseDegree { get { return MathHelper.ToDegrees(-_Radians); } set { Radians = MathHelper.ToRadians(-value); } }

        /// <summary>
        /// Initializes a new instance of the <see cref="Angle"/> struct.
        /// </summary>
        /// <param name="radians">The radians.</param>
        public Angle(float radians)
        {
            _Radians = MathHelper.WrapAngle(radians);
        }


        /// <summary>
        /// Gets the direction vector, which is a normalized vector pointing to the direction of this angle.
        /// </summary>
        public Vector2 GetDirectionVector()
        {
            return new Vector2((float)Math.Cos(ClockwiseRadians), (float)Math.Sin(ClockwiseRadians));
        }
        /// <summary>
        /// Sets the Angle by using a direction vector.
        /// </summary>
        public void SetDirectionVector(Vector2 direction)
        {
            ClockwiseRadians = (float)Math.Atan2(direction.Y, direction.X);
        }

        /// <summary>
        /// Rotates the given Vector around the zero point
        /// </summary>
        /// <param name="vector">the vector to rotate</param>
        /// <returns>the rotated vector</returns>
        public Vector2 RotateVector(Vector2 vector) 
        {
            if (_Radians == 0)
                return vector;

            Angle completeAngle = Angle.CreateFromVector(vector) + _Radians;
            return completeAngle.GetDirectionVector() * vector.Length();
        }

        public bool Equals(Angle other)
        {
            return this._Radians == other._Radians;
        }

        #region operators

        public static bool operator ==(Angle a, Angle b)
        {
            return a.Equals(b);
        }
        public static bool operator !=(Angle a, Angle b)
        {
            return !a.Equals(b);
        }
        public static bool operator ==(Angle a, float b)
        {
            return a._Radians == b;
        }
        public static bool operator !=(Angle a, float b)
        {
            return a._Radians != b;
        }
        public static bool operator ==(float a, Angle b)
        {
            return a == b._Radians;
        }
        public static bool operator !=(float a, Angle b)
        {
            return a != b._Radians;
        }
        /// <summary>
        /// Implements the operator + for two angles.
        /// </summary>
        /// <returns>The result of the operator.</returns>
        public static Angle operator +(Angle a, Angle b)
        {
            return new Angle(a._Radians+ b._Radians);
        }
        /// <summary>
        /// Implements the operator + for an angle and a float which represents radians.
        /// </summary>
        /// <returns>The result of the operator.</returns>
        public static Angle operator +(Angle a, float b)
        {
            return new Angle(a._Radians + b);
        }

        /// <summary>
        /// Implements the operator - for two angles.
        /// </summary>
        /// <returns>The result of the operator.</returns>
        public static Angle operator -( Angle a, Angle b)
        {
            return new Angle(a._Radians - b._Radians);
        }
        /// <summary>
        /// Implements the operator - for an angle and a float which represents radians.
        /// </summary>
        /// <returns>The result of the operator.</returns>
        public static Angle operator -(Angle a, float b)
        {
            return new Angle(a._Radians - b);
        }

        /// <summary>
        /// Implements the operator *.
        /// </summary>
        /// <returns>The result of the operator.</returns>
        public static Angle operator *(Angle a, float b)
        {
            return new Angle(a._Radians * b);
        }

        /// <summary>
        /// Implements the operator /.
        /// </summary>
        /// <returns>The result of the operator.</returns>
        public static Angle operator /(Angle a, float b)
        {
            return new Angle(a._Radians / b);
        }

        /// <summary>
        /// Performs an explicit conversion from <see cref="Shapes.Geometry.Angle"/> to <see cref="System.Single"/>.
        /// </summary>
        /// <param name="a">the angle.</param>
        /// <returns>The Radians of a.</returns>
        public static explicit operator Single(Angle a)
        {
            return a.Radians;
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="System.Single"/> to <see cref="Shapes.Geometry.Angle"/>.
        /// </summary>
        /// <param name="b">The value in radians.</param>
        /// <returns>The angle with b as radians.</returns>
        public static implicit operator Angle(Single b)
        {
            return new Angle(b);
        }

        #endregion


    }
}
